package com.platform.framework.gateway.alipay;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.log4j.Logger;
import org.springframework.stereotype.Component;

import com.alipay.demo.trade.config.Configs;
import com.alipay.demo.trade.model.GoodsDetail;
import com.alipay.demo.trade.model.builder.AlipayTradeCancelRequestBuilder;
import com.alipay.demo.trade.model.builder.AlipayTradePayRequestBuilder;
import com.alipay.demo.trade.model.builder.AlipayTradePrecreateRequestBuilder;
import com.alipay.demo.trade.model.builder.AlipayTradeQueryRequestBuilder;
import com.alipay.demo.trade.model.builder.AlipayTradeRefundRequestBuilder;
import com.alipay.demo.trade.model.builder.RequestBuilder;
import com.alipay.demo.trade.model.result.AlipayF2FPayResult;
import com.alipay.demo.trade.model.result.AlipayF2FPrecreateResult;
import com.alipay.demo.trade.model.result.AlipayF2FQueryResult;
import com.alipay.demo.trade.model.result.AlipayF2FRefundResult;
import com.alipay.demo.trade.model.result.AlipayF2FSettleResult;
import com.alipay.demo.trade.model.result.Result;
import com.alipay.demo.trade.service.AlipayTradeService;
import com.alipay.demo.trade.service.impl.AlipayTradeServiceImpl;
import com.platform.framework.entity.alipay.AlipayReturnInfo;
import com.platform.framework.entity.alipay.AliRefundReturnInfo;
import com.platform.framework.gateway.alipay.config.AlipayConfig;
import com.platform.framework.gateway.alipay.inf.AlipayGateway;
import com.platform.framework.util.net.httpvo.AlipaySubmit;
import com.platform.framework.util.pub.JsonUtil;
import com.platform.framework.util.pub.ReflectUtil;
import com.platform.framework.util.pub.Validation;
import com.platform.framework.vo.exception.ReceiverException;
import com.platform.framework.vo.states.PayGate;
import com.platform.framework.vo.states.PayResult;
import com.platform.framework.vo.transfer.TransportLayer;

@Component("alipayGateway")
public class AlipayGatewayImpl implements AlipayGateway{
	
	private static Logger log = Logger.getLogger(AlipayGatewayImpl.class);
	
	private static AlipayTradeService tradeService;
	
	private static AlipayTradeService getTradeServiceInstance() {
		if (tradeService == null) {
			tradeService = new AlipayTradeServiceImpl.ClientBuilder().build();
		}
		return tradeService;
	}
	
	@Override
	public AlipayReturnInfo aliBarcodePay(final TransportLayer transportLayer)
			throws Exception {
		AlipayF2FPayResult result = this.excute(transportLayer,new AlipayFunction<AlipayTradeService,RequestBuilder, AlipayF2FPayResult>() {
			@Override
			public AlipayF2FPayResult callback(AlipayTradeService tradeService ,RequestBuilder builder) {
				log.info("[tradelog:"+transportLayer.getOrderNo()+"]builder info:"+((AlipayTradePayRequestBuilder)builder).toJsonString());
				Result result = tradeService.tradePay((AlipayTradePayRequestBuilder)builder); // 调用SDK支付接口
				recordResultLog(transportLayer,result); // 记录日志
				return (AlipayF2FPayResult)result;
			}
		});
		AlipayReturnInfo alipayReturnInfo = ReflectUtil.voPersistence(new AlipayReturnInfo(), result.getResponse());
		alipayReturnInfo.setPayResult(getPayResultFromSDKResult(result,transportLayer));
		transportLayer.setTradeNo(alipayReturnInfo.getTradeNo());
		return alipayReturnInfo;
	}

	@Override
	public AliRefundReturnInfo aliTradeRefund(final TransportLayer transportLayer)
			throws Exception {
		AlipayF2FRefundResult result = this.excute(transportLayer, new AlipayFunction<AlipayTradeService, RequestBuilder, AlipayF2FRefundResult>() {
			@Override
			public AlipayF2FRefundResult callback(AlipayTradeService tradeService,
					RequestBuilder builder) {
				log.info("[tradelog:"+transportLayer.getOrderNo()+"]builder info:"+((AlipayTradeRefundRequestBuilder)builder).toJsonString());
				Result result = tradeService.tradeRefund((AlipayTradeRefundRequestBuilder)builder);
				recordResultLog(transportLayer,result); // 记录日志
				return (AlipayF2FRefundResult)result;
			}
		});
		AliRefundReturnInfo alirefundReturnInfo = ReflectUtil.voPersistence(new AliRefundReturnInfo(), result.getResponse());
		alirefundReturnInfo.setPayResult(getPayResultFromSDKResult(result,transportLayer));
		return alirefundReturnInfo;
	}

	@Override
	public String alipaySettle(TransportLayer transportLayer) throws Exception {
		return null;
	}

	@Override
	public String generateQRCode(final TransportLayer transportLayer)
			throws Exception {
		AlipayF2FPrecreateResult result = this.excute(transportLayer, new AlipayFunction<AlipayTradeService, RequestBuilder, AlipayF2FPrecreateResult>() {
			@Override
			public AlipayF2FPrecreateResult callback(AlipayTradeService tradeService,
					RequestBuilder builder) {
				log.info("[tradelog:"+transportLayer.getOrderNo()+"]builder info:"+((AlipayTradePrecreateRequestBuilder)builder).toJsonString());
				return tradeService.tradePrecreate((AlipayTradePrecreateRequestBuilder)builder); // 调用SDK QRCode支付 预下单得到QRCode
			}
		});
		log.info("[tradelog"+transportLayer.getOrderNo()+"]prepay return info :" + JsonUtil.Object2Json(result.getResponse()));
		return result.getResponse().getQrCode(); // 返回二维码Url
	}

	@Override
	public String queryTradeResult(final TransportLayer transportLayer)
			throws Exception {
		AlipayF2FQueryResult result = this.excute(transportLayer, new AlipayFunction<AlipayTradeService,RequestBuilder, AlipayF2FQueryResult>() {
			@Override
			public AlipayF2FQueryResult callback(AlipayTradeService tradeService,RequestBuilder builder) {
				log.info("[tradelog:"+transportLayer.getOrderNo()+"]builder info:"+((AlipayTradeQueryRequestBuilder)builder).toJsonString());
				Result result = tradeService.queryTradeResult((AlipayTradeQueryRequestBuilder)builder); // 调用SDK查询接口
				recordResultLog(transportLayer,result); // 记录日志
				return (AlipayF2FQueryResult)result;
			}
		});
		String buyerUserId = result.getResponse().getBuyerUserId();
		transportLayer.setBuyerUserId(buyerUserId);
		return getPayResultFromSDKResult(result,transportLayer);
	}

	@Override
	public String aliPCpay(TransportLayer transportLayer) {
		//服务器异步通知页面路径
		String notify_url = AlipayConfig.serverBaseUrl + "alipay/notifyInfoWap";
		//需http://格式的完整路径，不能加?id=123这类自定义参数
		//页面跳转同步通知页面路径
		String return_url = AlipayConfig.serverBaseUrl + "";
		//客户端的IP地址
		String exter_invoke_ip = "";
		//支付宝key值
		String aliKey = transportLayer.getAliKey();
		//防钓鱼时间戳
		String anti_phishing_key = "";
		try {
			anti_phishing_key = AlipaySubmit.query_timestamp();
		} catch (Exception e) {
			e.printStackTrace();
		}
		//把请求参数打包成数组
		Map<String, String> sParaTemp = new HashMap<String, String>();
		sParaTemp.put("service", "create_direct_pay_by_user");
        sParaTemp.put("partner", transportLayer.getPid());
        sParaTemp.put("seller_email", transportLayer.getAlipayAccount());
        sParaTemp.put("_input_charset", AlipayConfig.input_charset);
		sParaTemp.put("payment_type","1");
		sParaTemp.put("notify_url", notify_url);
		sParaTemp.put("return_url", return_url);
		sParaTemp.put("out_trade_no", transportLayer.getOutTradeNo());
		sParaTemp.put("subject", transportLayer.getSubject());
		sParaTemp.put("total_fee", transportLayer.getTotalAmount());
		sParaTemp.put("body", transportLayer.getBody());
		sParaTemp.put("show_url",null);
		sParaTemp.put("anti_phishing_key", anti_phishing_key);
		sParaTemp.put("exter_invoke_ip", "0:0:0:0:0:0:0:1");
		//建立请求
		log.info("[AlipayUtils.toAlipayPC] sParaTemp = ["+sParaTemp+"] ");
		String sHtmlText = AlipaySubmit.buildRequest(sParaTemp,"get","确认",aliKey);
		return sHtmlText;
	}

	@Override
	public String aliWapPay(TransportLayer transportLayer) {
		//服务器异步通知页面路径
		String notify_url = AlipayConfig.serverBaseUrl + "/api/trade/aliNotifyInfo";
		//需http://格式的完整路径，不能加?id=123这类自定义参数
		//页面跳转同步通知页面路径
		String return_url = AlipayConfig.serverBaseUrl + "";
		// show url
		String show_url = AlipayConfig.serverBaseUrl + "";

		//支付宝key值
		String aliKey = transportLayer.getAliKey();
		
		//把请求参数打包成数组
		Map<String, String> sParaTemp = new HashMap<>();
		sParaTemp.put("service", "alipay.wap.create.direct.pay.by.user");
        sParaTemp.put("partner", transportLayer.getPid());
        sParaTemp.put("seller_id", transportLayer.getPid());
        sParaTemp.put("_input_charset", AlipayConfig.input_charset);
		sParaTemp.put("payment_type", "1");
		sParaTemp.put("notify_url", notify_url);
		sParaTemp.put("return_url", return_url);
		sParaTemp.put("out_trade_no", transportLayer.getOutTradeNo());
		sParaTemp.put("subject", transportLayer.getSubject());
		sParaTemp.put("total_fee", transportLayer.getTotalAmount());
		sParaTemp.put("show_url", show_url);
		sParaTemp.put("body", transportLayer.getBody());
		//建立请求
		log.info("[AlipayUtils.toAlipayWAP] sParaTemp = ["+sParaTemp+"] ");
		String sHtmlText = AlipaySubmit.buildRequest(sParaTemp,"get","确认",aliKey);
		return sHtmlText;
	}

	@Override
	public String cancelTrade(final TransportLayer transportLayer) throws Exception {
		String result = this.excute(transportLayer, new AlipayFunction<AlipayTradeService, RequestBuilder,String>() {
			@Override
			public String callback(AlipayTradeService tradeService, RequestBuilder builder)
					throws Exception {
				log.info("[tradelog:"+transportLayer.getOrderNo()+"]builder info:"+((AlipayTradeCancelRequestBuilder)builder).toJsonString());
				return tradeService.manualTradeCancel((AlipayTradeCancelRequestBuilder)builder);
			}
		});
		log.info("撤单成功，撤单结果为：" + result);
		return result;
	}
	
	/**
	 * 记录SDK回调日志信息
	 * @param result
	 */
	private static void recordResultLog (TransportLayer transportLayer,Result result) {
		String jsonResult = "";
		try {
			if (transportLayer.getPayGate().equals(PayGate.BAR_CODE_PAY)) { // 条码支付SDK调用返回日志记录
				AlipayF2FPayResult payResult = (AlipayF2FPayResult)result;
				jsonResult = JsonUtil.Object2Json(payResult.getResponse());
			} else if (transportLayer.getPayGate().equals(PayGate.QUERY_TRADE_RESULT)) { // 查询SDK调用返回日志记录
				AlipayF2FQueryResult queryResult = (AlipayF2FQueryResult)result;
				jsonResult = JsonUtil.Object2Json(queryResult.getResponse());
			} else if (transportLayer.getPayGate().equals(PayGate.TRADE_REFUND)) { // 支付SDK退款返回日志
				AlipayF2FRefundResult refundResult = (AlipayF2FRefundResult)result;
				jsonResult = JsonUtil.Object2Json(refundResult.getResponse());
			} else if (transportLayer.getPayGate().equals(PayGate.ALI_SETTLE)) {
				log.info("[tradelog:"+transportLayer.getOrderNo()+"]分润返回信息为：");
				AlipayF2FSettleResult settleResult = (AlipayF2FSettleResult)result;
				jsonResult = JsonUtil.Object2Json(settleResult.getSettleResponse());
			}
		} catch (Exception e) {
			log.error("[tradelog:"+transportLayer.getOrderNo()+"]SDK记录日志报错！");
			e.printStackTrace();
		}
		log.info("[tradelog:"+transportLayer.getOrderNo()+"]payresult is : "+jsonResult);
	}

	
	/**
	 * sdk tradeService 的回调方法
	 * 执行者：AlipayTradeService
	 * 需要参数：builder
	 * 返回：泛型参数
	 * ps:需要同步
	 * @param fun
	 * @throws Exception 
	 */
	private synchronized <T> T excute (TransportLayer transportLayer,AlipayFunction<AlipayTradeService,RequestBuilder, T> fun) throws Exception {
		initConfig(transportLayer);
		RequestBuilder builder = vo2builder(transportLayer);
		return fun.callback(getTradeServiceInstance(),builder);
	}
	
	/**
	 * requestVo到builder的创建方法
	 * @param transportLayer
	 * @return
	 * @throws ReceiverException 
	 */
	@SuppressWarnings("unchecked")
	private static RequestBuilder vo2builder (TransportLayer transportLayer) throws ReceiverException {
		
		if (transportLayer.getPayGate().equals(PayGate.QUERY_TRADE_RESULT)) {
			// 如果是查询订单状态，只需要订单号一个参数
			AlipayTradeQueryRequestBuilder queryBuilder = new AlipayTradeQueryRequestBuilder();
			return queryBuilder.setOutTradeNo(transportLayer.getOutTradeNo());
		} else if (transportLayer.getPayGate().equals(PayGate.BAR_CODE_PAY)) {
			// 支付订单需要参数
			AlipayTradePayRequestBuilder payBuilder = new AlipayTradePayRequestBuilder();;
			List<GoodsDetail> list = (List<GoodsDetail>)JsonUtil.Json2Object(transportLayer.getDetail(),List.class);
			if (Validation.isEmptyList(list) ) { // 需要传递商品信息至支付宝，如果没有，则把body信息传至支付宝。
				GoodsDetail goodsDetail = new GoodsDetail();
				goodsDetail.setGoodsId("");
				goodsDetail.setGoodsName(transportLayer.getBody());
				goodsDetail.setPrice(Math.round(Double.parseDouble(transportLayer.getTotalAmount())));
				goodsDetail.setQuantity(1);
				list = new ArrayList<GoodsDetail>();
				list.add(goodsDetail);
			}
			
			if (!Validation.isEmpty(transportLayer.getSubAccountId())) { // subAccountId不为空，证明有子账户参与支付，这时必须要有sellerid 或者storeid
				if (!Validation.isEmpty(transportLayer.getIsSettle()) && transportLayer.getIsSettle().equals("true")) { // 调起分润
					payBuilder.setSellerId("");
					payBuilder.setStoreId(AlipayConfig.storeId);
				} else if (!Validation.isEmpty(transportLayer.getStoreId())) {
					payBuilder.setStoreId(transportLayer.getStoreId());
					payBuilder.setSellerId(AlipayConfig.sellerId);
				} else if (!Validation.isEmpty(transportLayer.getSellerId())) {
					payBuilder.setSellerId(transportLayer.getSellerId());
					payBuilder.setStoreId(AlipayConfig.storeId);
				} else {
					log.error("[tradelog:"+transportLayer.getOrderNo()+"]sellerId或storeId 为空，不给调起支付。");
					throw new ReceiverException("[tradelog:"+transportLayer.getOrderNo()+"]sellerId or storeId is null");
				}
			} else {
				payBuilder.setSellerId("");
				payBuilder.setStoreId(AlipayConfig.storeId);
			}
			
			
			payBuilder.setOutTradeNo(transportLayer.getOutTradeNo())
			.setSubject(transportLayer.getSubject())
			.setAuthCode(transportLayer.getAuthCode())
			.setTotalAmount(transportLayer.getTotalAmount())
			.setNotifyUrl(AlipayConfig.notifyUrl)
			.setBody(transportLayer.getBody())
			.setGoodsDetailList(list)
//			.setOperatorId(AlipayConfig.operatorId)
			.setTimeoutExpress(AlipayConfig.timeoutExpress);
			return payBuilder;
		} else if (transportLayer.getPayGate().equals(PayGate.TRADE_REFUND)) {
			 // 创建退款请求builder，设置请求参数
	        AlipayTradeRefundRequestBuilder refundBuilder = new AlipayTradeRefundRequestBuilder()
	                .setOutTradeNo(transportLayer.getOutTradeNo())
	                .setRefundAmount(transportLayer.getRefundAmount())
	                .setRefundReason(transportLayer.getRefundReason())
	                .setOutRequestNo(AlipayConfig.outRequestNo);
	        if (!Validation.isEmpty(transportLayer.getSubAccountId()) ) { // 如果subAccountId为空，证明是主账号本身发起退款请求，没有子账户参与。
	        	if (!Validation.isEmpty(transportLayer.getStoreId())) { 
	        		refundBuilder.setStoreId(transportLayer.getStoreId());
	        	} else {
	        		log.error("[tradelog:"+transportLayer.getOrderNo()+"]storeId 为空，不给调起退款。");
	        		throw new ReceiverException("storeId is null");
	        	}
	        }
	        
	        if (!Validation.isEmpty(transportLayer.getOutRequestNo())) {
	        	refundBuilder.setOutRequestNo(transportLayer.getOutRequestNo());
	        }
	        return refundBuilder;
		} else if (transportLayer.getPayGate().equals(PayGate.QRCODE_PAY)) {
			 AlipayTradePrecreateRequestBuilder qrPayBuilder = new AlipayTradePrecreateRequestBuilder();
				List<GoodsDetail> list = (List<GoodsDetail>)JsonUtil.Json2Object(transportLayer.getDetail(),List.class);
				if (!Validation.isEmpty(transportLayer.getSubAccountId()) ) { 
					if (!Validation.isEmpty(transportLayer.getSellerId())) {
						qrPayBuilder.setSellerId(transportLayer.getSellerId());
					} else if (!Validation.isEmpty(transportLayer.getStoreId())) {
						qrPayBuilder.setStoreId(transportLayer.getStoreId());
						qrPayBuilder.setSellerId(AlipayConfig.sellerId);
					} else {
						log.error("[tradelog:"+transportLayer.getOrderNo()+"]sellerId 或 storeId 为空，不给调起支付。");
						throw new ReceiverException("sellerId or storeId is null");
					}
				}
				qrPayBuilder.setSubject(transportLayer.getSubject())
                .setTotalAmount(transportLayer.getTotalAmount())
                .setOutTradeNo(transportLayer.getOutTradeNo())
                .setBody(transportLayer.getBody())
                .setTimeoutExpress(AlipayConfig.QR_TIMEOUT)
                .setNotifyUrl(AlipayConfig.notifyUrl)//支付宝服务器主动通知商户服务器里指定的页面http路径,根据需要设置
                .setGoodsDetailList(list);
				return qrPayBuilder;
		} else if (transportLayer.getPayGate().equals(PayGate.CANCEL_TRADE)) { // 支付宝撤单
			AlipayTradeCancelRequestBuilder builder = new AlipayTradeCancelRequestBuilder();
			builder.setOutTradeNo(transportLayer.getOutTradeNo());
			return builder;
		}
		
		return null;
	}
	
	/**
	 * 初始化支付配置，从商户账户表中读取appid、key等关键支付信息以初始化
	 * Configs 为全局变量，为了避免资源竞争，做同步锁处理。
	 */
	private void initConfig (TransportLayer transportLayer) {
		Configs.init("zfbinfo.properties");
		Configs.setAppid(transportLayer.getAppid());
		Configs.setPid(transportLayer.getPid());
		Configs.setPrivateKey(transportLayer.getPrivateKey());
		Configs.setPublicKey(transportLayer.getPublicKey());
		Configs.setAlipayPublicKey(transportLayer.getAlipayPublicKey());
		log.info(Configs.description());
//		if ("true".equals(transportLayer.getIsSettle())) { // 分润字段设置
//			if (Validation.isEmpty(transportLayer.getSubAccountId())) {
//				transportLayer.setTransOut(transportLayer.getPid());
//			}
//			double splitRatio = Double.parseDouble(transportLayer.getSplitRatio());
//			double totalAmount = Double.parseDouble(transportLayer.getTotalAmount());
//			double settleAmount = totalAmount * splitRatio;
//			transportLayer.setSettleAmount(String.valueOf(settleAmount));
//		}
	}
	
	/**
	 * 此处交易未知包含在交易失败在内
	 * 扫码支付时，顾客未付款，查询出的交易结果也是FAILED，请注意。
	 * @param result
	 * @return
	 */
	private static String getPayResultFromSDKResult (Result result,TransportLayer transportLayer) {
		
		if (result.isTradeSuccess()) {
			if (transportLayer.getPayGate().equals(PayGate.TRADE_REFUND)) {
				return PayResult.REFUND_SUCCESS;
			}
			if (result.getClass().equals(AlipayF2FSettleResult.class)) {
				return PayResult.TRADE_SETTLE_SUCCESS;
			}
			return PayResult.TRADE_SUCCESS;
		} else {
			if (transportLayer.getPayGate().equals(PayGate.TRADE_REFUND))  {
				return PayResult.REFUND_FAIL;
			}
			if (result.getClass().equals(AlipayF2FSettleResult.class)) {
				return PayResult.TRADE_SETTLE_FAIL;
			}
			return PayResult.TRADE_FAIL;
		}
	}
	
}
